[RUN-4595] ReImplement Functional Tests#428
Open
fdevans wants to merge 11 commits into
Open
Conversation
Rundeck 6's AsyncImportService expects explicit directory entries (with trailing /) in project archives. Without them, directories like "jobs" extract as zero-byte files, causing "Not a directory" errors during import. Changes: - Collect all parent directories from file paths - Create JarEntry objects with trailing / for each directory - Write directory entries before file entries, ordered shallow-to-deep - Normalize paths to use forward slashes This ensures archives are compatible with both Rundeck 5 and 6 import mechanisms.
Contributor
Author
|
@copilot resolve the merge conflicts in this pull request |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the functional/integration test harness to align with Rundeck 6 / Grails 7 expectations (project creation/import semantics, archive format quirks) and improves CI visibility by capturing and uploading full Gradle/test logs.
Changes:
- Switch functional tests to use a Rundeck 6.x-aligned version catalog entry and propagate it into the functional test configuration.
- Rework project archive generation and project import/setup helpers for Rundeck 6 async import behavior and Grails 7 project creation requirements.
- Improve CI diagnostics by tee’ing Gradle output to non-hidden directories and uploading logs/reports as artifacts.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| gradle/libs.versions.toml | Pins the Rundeck core version used by the build/test setup. |
| functional-test/src/test/groovy/functional/util/TestUtil.groovy | Adjusts project archive creation (manifest versioning + explicit directory entries). |
| functional-test/src/test/groovy/functional/MultiNodeAuthSpec.groovy | Refactors setup to reuse new Grails 7 project creation/import helpers; updates OkHttp RequestBody usage. |
| functional-test/src/test/groovy/functional/base/RundeckCompose.groovy | Adds helper to dump Rundeck container logs on failures. |
| functional-test/src/test/groovy/functional/base/BaseTestConfiguration.groovy | Centralizes project creation/import + adds config-time “touch” for resource refresh and better import failure diagnostics. |
| functional-test/README.md | Updates prerequisites to Java 17 / Gradle 8. |
| functional-test/build.gradle | Wires Rundeck version into test system properties; enables verbose test logging. |
| .gitignore | Ignores new ci-logs/ output directory. |
| .github/workflows/gradle.yml | Always runs functional tests on push and uploads logs/reports as artifacts. |
Comment on lines
+198
to
+208
| def waitForNodeAvailability(String projectName, String nodeName) { | ||
| touchProjectConfigTime(projectName) | ||
| final long deadlineNanos = System.nanoTime() + TimeUnit.MINUTES.toNanos(3) | ||
| def result = client.apiCall { api -> api.listNodes(projectName, ".*") } | ||
|
|
||
| while (result.get(nodeName) == null && System.nanoTime() < deadlineNanos) { | ||
| touchProjectConfigTime(projectName) | ||
| sleep(3000) | ||
| result = client.apiCall { api -> api.listNodes(projectName, ".*") } | ||
| } | ||
| } |
Comment on lines
+48
to
+52
| def opt = getContainerByServiceName("rundeck") | ||
| if (!opt.isPresent()) { | ||
| System.err.println("${header}\n(no rundeck service container in compose state)") | ||
| return | ||
| } |
Comment on lines
+40
to
+43
| // Rundeck Docker image tag must match `rundeck-core` in ../gradle/libs.versions.toml (single source of truth). | ||
| systemProperty('RUNDECK_TEST_IMAGE', "rundeck/rundeck:${libs.versions.rundeck.core.get()}") | ||
| // Project archive manifest must match server generation; see TestUtil.createArchiveJarFile | ||
| systemProperty('RUNDECK_ARCHIVE_APP_VERSION', libs.versions.rundeck.core.get()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Re-enables and modernizes the Testcontainers functional test suite so it runs on
every CI build and passes against Rundeck 6 (Grails 7). Previously these tests ran
only on
main/tag builds and were incompatible with Rundeck 6's project-import andREST API behavior, so they gave no coverage during day-to-day development.
What changed
CI/CD (
.github/workflows/gradle.yml)main/tags-only guards oncopyPluginArtifactandfunctionalTest).functionalTestruns with--stacktrace --info, teeing the full Gradle transcriptto two locations (
ci-logs/andfunctional-test/build/ci-reports/) to work aroundupload-artifactskipping dot-directories..gitignore: ignoreci-logs/.Rundeck 6 / Grails 7 compatibility (
functional-test/)RUNDECK_TEST_IMAGEand the newRUNDECK_ARCHIVE_APP_VERSIONare derived from
rundeck-coreingradle/libs.versions.tomlinstead of hardcoded5.18.0/5.0.0.TestUtil.createArchiveJarFile): stampRundeck-Application-Versionfrom
RUNDECK_ARCHIVE_APP_VERSION(default6.0.0, since Rundeck 6 rejects5.x-stampedarchives); write explicit directory entries (trailing
/, shallow-to-deep) before files soAsyncImportServiceno longer treatsjobs/as a zero-byte file ("Not a directory").Compatible with both Rundeck 5 and 6.
createProjectGrails7IfMissing): Grails 7POST /projectsrequirestop-level
nameplusconfig["project.name"].RequestBody.create(MediaType, body)argument order.waitForNodeAvailability): nudges resource providers viaPUT project/{project}/config/timeand polls up to 3 minutes (was a fixed 5×2s loop).Diagnostics
importProjectArchiveFromTestResourcesparsesProjectImportStatusand, on failure,logs the pretty-printed status JSON and dumps (truncated) Rundeck container logs to stderr
(
RundeckCompose.appendRundeckContainerLogsToStdErr).testLogging(failed/passed/skipped/stdout/stderr, full exceptions, stack traces).Docs
functional-test/README.md: prerequisites bumped to Java 17 / Gradle 8.Test plan
./gradlew build./gradlew :functional-test:copyPluginArtifact :functional-test:functionalTest(Docker running) passes against the Rundeck image pinned by
rundeck-core.